package test.patterns;

import java.util.*;
/** Demonstation of the Command pattern.
    The main method plays the Invoker role.
 
   This source code is from the book 
     "Flexible, Reliable Software:
       Using Patterns and Agile Development"
     published 2010 by CRC Press.
   Author: 
     Henrik B Christensen 
     Computer Science Department
     Aarhus University
   
   This source code is provided WITHOUT ANY WARRANTY either 
   expressed or implied. You may study, use, modify, and 
   distribute it for non-commercial purposes. For any 
   commercial use, see http://www.baerbak.com/
*/
public class CommandDemo {
  public static void main(String[] args) {
    System.out.println( "======= Demonstration of Command =======");
    Document doc = new Document();

    String line1 = "Chapter: The command pattern.";
    String line2 = "Section 1: Problem";
    String line3 = "Command is a pattern that makes behavior an object.";

    System.out.println( "======= First - using method calls =======" );
    doc.write(line1);
    doc.write(line2);
    doc.write(line3);
    System.out.println( doc );

    System.out.println( "---> Erasing last entered line" );
    doc.erase(line3);
    System.out.println( doc );

    
    System.out.println( "======= Next - command objects assigned to F1..F3 =======" );
    doc = new Document();
    // Create the commands
    Command write1, write2, write3;
    write1 = new WriteCommand(doc, line1);
    write2 = new WriteCommand(doc, line2);
    write3 = new WriteCommand(doc, line3);
    // Note - nothing has happened to the document yet!
    
    // assign bindings to the F1 keys
    FKey F1 = new FKey(), F2 = new FKey(), F3 = new FKey();
    // assign write commands to the keys
    F1.assign(write1);
    F2.assign(write2);
    F3.assign(write3);
    
    // next press F1 to F3 and see the result in the document
    F1.press(); F2.press(); F3.press();
    System.out.println( doc );
    
    // reassigning F2
    System.out.println( "======= F2 reassigned and pressed =======" );
    Command write4 = new WriteCommand(doc,"A wrong line");
    F2.assign(write4);
    F2.press();
    System.out.println( doc );

    // undoing the last operation
    System.out.println( "======= Undo of last insert =======" );
    write4.undo();
    System.out.println( doc );
  }
}

/** This class is a simple document, it acts as the
 * Receive role in the Command pattern
 */
class Document {   
  private List<String> contents = new ArrayList<String>();
  public void write(String text) {
    contents.add(text);
  }
  public void erase(String text) {
    contents.remove(text);
  }
  public String toString() {
    String result = new String();
    for ( String line : contents ) {
      result += line+"\n";
    }
    return result;
  }
}        

/** The interface defining the Command role */
interface Command {
  public void execute();
  public void undo();
}

/** A concrete command to write text to the document */
class WriteCommand implements Command {
  private Document doc;
  private String line;
  public WriteCommand(Document doc, String line) {
    this.doc = doc; this.line = line;
  }
  public void execute() {
    doc.write(line);
  }
  public void undo() {
    doc.erase(line); 
  }
}

/** A class representing a function key on keyboard */
class FKey {
  private Command command;
  /** assign a command to the key */
  public void assign(Command command) {
    this.command = command;
  }
  /** "press the key" */
  public void press() {
    command.execute();
  }
}
